//
//  CertUtil.m
//  TestProject
//
//  Created by 毕武侠 on 2022/2/7.
//  Copyright © 2022 zhulong. All rights reserved.
//

#import "CertUtil.h"
#import "CertOID.h"
#import "CertItemLength.h"

static const unichar kBase64DecodeChars[] = {
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      62/*+*/, 99,      99,      99,      63/*/ */,
    52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
    60/*8*/, 61/*9*/, 99,      99,      99,      99,      99,      99,
    99,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
    7/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
    15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
    23/*X*/, 24/*Y*/, 25/*Z*/, 99,      99,      99,      99,      99,
    99,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
    33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
    41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
    49/*x*/, 50/*y*/, 51/*z*/, 99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99,
    99,      99,      99,      99,      99,      99,      99,      99
};


// X509 扩展
@implementation X509Extension
@end

// 证书结构
@implementation Certificate

@end

// X509结构

@interface X509Cert ()

@property (nonatomic, strong) NSData *data;

@end

@implementation X509Cert

- (instancetype)initWithBase64:(NSString *)data {
    self = [super init];
    // 1: 解析base64
    self.data = [self decodeBase64Info:data];
    
    // 2: 解析证书
    [self decomposeX509:(char *)[self.data bytes]];
    return self;
}

// 30 82 02 D2 30 82 02 75 A0 03 02 01 02
// 分解X509
- (void)decomposeX509:(char *)data {
    int begin = 0;
    CertItemLength *length = [[CertItemLength alloc] initWithData:data index:begin+1];
    begin += 1 + length.lenLen;
    
    // 1: 解析证书
    length = [[CertItemLength alloc] initWithData:data index:begin+1];
    self.certficate = [self decomposeCert:data begin:begin+1+length.lenLen end:begin+1+length.len+length.lenLen];
    
    // 2: 解析证书签名算法
    begin += 1 + length.len + length.lenLen;
    length = [[CertItemLength alloc] initWithData:data index:begin+1];
    self.signatureAlgorithm = [self signature:data begin:begin length:length];
    
    // 3: 解析数字签名
    begin += 1 + length.lenLen + length.len;
    self.certficateSignature = [CertTLV value:data begin:begin];
}

// 分解证书
- (Certificate *)decomposeCert:(char *)data begin:(int)begin end:(int)end {
    Certificate *certficate = [[Certificate alloc] init];
    
    int index = 0;
    int i = begin;
    while (i < end) {
        CertItemLength *length = [[CertItemLength alloc] initWithData:data index:i+1];
        switch (index) {
            case 0:
                certficate.version = [self version:data begin:i length:length];
                break;
            case 1:
                certficate.serialNumber = [self serialNumber:data begin:i length:length];
                break;
            case 2:
                certficate.signature = [self signature:data begin:i length:length];
                break;
            case 3:
                certficate.issuer = [self issuer:data begin:i length:length];
                break;
            case 4:
            {
                NSArray<NSString *> *array = [self time: data begin:i length: length];
                certficate.notBefore = array.count > 0 ? array[0] : @"";
                certficate.notAfter  = array.count > 1 ? array[1] : @"";
            }
                break;
            case 5:
                certficate.subject = [self subject:data begin:i length:length];
                break;
            case 6:
                certficate.publicKeyInfo = [self subjectPublicKeyInfo:data begin:i length:length];
                break;
            default:
                if ((uint8_t)data[i] == 0xa3) {
                    certficate.extensions = [self extensions:data begin:i length:length];
                }
                break;
        }
        
        i += 1 + length.len + length.lenLen;
        index += 1;
    }
    
    return certficate;
}

// 解析版本号
- (NSString *)version: (char *)data begin: (int)begin length: (CertItemLength *)length {
    int type = data[begin];
    if ((uint8_t)type != 0xa0) {
        return @"error";
    }
    NSString *v = [CertTLV value:data begin:begin+1+length.lenLen];
    if ([v isEqual:@"2"]) {
        return @"V3";
    } else if ([v isEqual:@"1"]) {
        return @"V2";
    } else if ([v isEqual:@"0"]) {
        return @"V1";
    } else {
        return @"未知类型";
    }
}

/*
 解析：序列号 serial Number
 02 05 20 50 51 03 79
 */
- (NSString *)serialNumber: (char *)data begin: (int)begin length: (CertItemLength *)length {
    int type = data[begin];
    if ((uint8_t)type != 0x02) {
        return @"error";
    }
    return [CertTLV value:data begin:begin];
}

/*
 解析：算法 signatureAlgorithm
 30 0C(12):
    06 08(08): 2A 81 1C CF 55 01 83 75
    05 00
 */
- (NSArray<NSString *> *)signature: (char *)data begin: (int)begin length: (CertItemLength *)length {
    int type = data[begin];
    if ((uint8_t)type != 0x30) {
        return @[];
    }
    
    NSMutableArray<NSString *> *array = [NSMutableArray array];
    int i = begin + 1 + length.lenLen;
    while (i < begin + 1 + length.len + length.lenLen) {
        CertItemLength *slength = [[CertItemLength alloc] initWithData:data index:i+1];
        NSString *sa = [CertTLV value:data begin:i];
        if (sa.length > 0) {
            [array addObject:sa];
        }
        i += 1 + slength.len + slength.lenLen;
    }
    return array;
}

/*
 解析：颁发者 issuer
 30 5D(93):
    31 0B(12): 30 09: [06 03: 55 04 06,  13 02: 43 4E]
    31 30(49): 30 2E: [06 03: 55 04 0A,  0C 27: 43 68 69 6E 61 ...]
    31 1C(29): 30 1A: [06 03: 55 04 03,  0C 13: 43 46 43 41 20 ...]
 */
- (NSArray<NSArray<NSString *> *> *)issuer: (char *)data begin: (int)begin length: (CertItemLength *)length {
    int type = data[begin];
    if ((uint8_t)type != 0x30) {
        return @[];
    }
    int i = begin + 1 + length.lenLen;
    NSMutableArray<NSArray<NSString *> *> *array = [NSMutableArray array];
    while (i < begin + 1 + length.len + length.lenLen) {
        type = data[i];
        if ((uint8_t)type != 0x31) {
            break;
        }
        CertItemLength *slength = [[CertItemLength alloc] initWithData:data index:i+1];
        i += 1 + slength.lenLen;
        type = data[i];
        if ((uint8_t)type != 0x30) {
            break;
        }
        slength = [[CertItemLength alloc] initWithData:data index:i+1];
        i += 1 + slength.lenLen;
        type = data[i];
        if ((uint8_t)type != 0x06) {
            break;
        }
        NSString *oid = [CertTLV value:data begin:i];
        
        slength = [[CertItemLength alloc] initWithData:data index:i+1];
        i += 1 + slength.lenLen + slength.len;
        
        NSString *value = [CertTLV value:data begin:i];
        slength = [[CertItemLength alloc] initWithData:data index:i+1];
        i += 1 + slength.lenLen + slength.len;
        [array addObject:@[oid, value]];
    }
    
    return array;
}

/*
 解析：时间 time
 30 1E(30):
    17 0D(13): 32 31 31 31 31 37 30 37 30 30 33 30 5A
    17 0D(13): 32 32 31 31 31 37 30 37 30 30 33 30 5A
 */
- (NSArray<NSString *> *)time: (char *)data begin: (int)begin length: (CertItemLength *)length {
    int type = data[begin];
    if ((uint8_t)type != 0x30) {
        return @[];
    }
    
    NSMutableArray<NSString *> *array = [NSMutableArray array];
    int i = begin + 1 + length.lenLen;
    while (i < begin + 1 + length.len + length.lenLen) {
        CertItemLength *slength = [[CertItemLength alloc] initWithData:data index:i+1];
        NSString *sa = [CertTLV value:data begin:i];
        if (sa.length > 0) {
            [array addObject:sa];
        }
        i += 1 + slength.len + slength.lenLen;
    }
    return array;
}

/*
 解析：主题 subject
 30 74(116)
    31 0B(11): 30 09 [06 03(03): 55 04 06, 13 02(02): 43 4E]
    31 15(21): 30 13 [06 03(03): 55 04 0A, 0C 0C(12): 43 46 43 41 20 54 45 53 54 20 43 41]
    31 0E(14): 30 0C [06 03(03): 55 04 0B, 0C 05(12): 5A 5A 4A 58 57]
    31 19(25): 30 17 [06 03(03): 55 04 0B, 0C 10(16): 4F 72 67 61 6E 69 7A 61 74 69 6F 6E 61 6C 2D 32]
    31 23(35): 30 21 [06 03(03): 55 04 03, 0C 1A(26): 30 35 31 40 E6 B5 8B E8 AF 95 E4 BC 81 E4 B8 9A 40 5A 31 32 33 34 35 36 40 31]
 */
- (NSArray<NSArray<NSString *> *> *)subject: (char *)data begin: (int)begin length: (CertItemLength *)length {
    return [self issuer:data begin:begin length:length];
}

/*
 解析：主题公钥算法
 30 59(89)
    30 13(19):
        06 07: 2A 86 48 CE 3D 02 01
        06 08: 2A 81 1C CF 55 01 82 2D
    03 42(66): 00 04 C9 B4 EE ...
 解析：主题公钥算法 一证通
 30 81 9F(159):
    30 0D(13):
        06 09:(09) 2A 86 48 86 F7 0D 01 01 01
        05 00
    03 81 8D(141):
        00 30 81 89 02 81 ...
 */
- (CertPublicKeyInfo *)subjectPublicKeyInfo: (char *)data begin: (int)begin length: (CertItemLength *)length {
    int type = data[begin];
    if ((uint8_t)type != 0x30) {
        return nil;
    }
    
    NSData *sData = [NSData dataWithBytes:data + begin length:1+length.lenLen+length.len];
    return  [[CertPublicKeyInfo alloc] initWithData:sData];
}

/*
 解析：扩展字段
 A3 82 01 07(263):
    30 82 01 03(259):
        30 1F(31):
            06 03(03): 55 1D 23     (2.5.29.35)
            04 18(24):
                30 16(22):          (bea67e4d3d7c8fa055e6c12f092e2c2043b3427f)
                    80 14(20): BE A6 7E 4D 3D 7C 8F A0 55 E6 C1 2F 09 2E 2C 20 43 B3 42 7F
        30 0C(12):
            06 03(03): 55 1D 13     (2.5.29.19)
            01 01(01): FF           (true)
            04 02(02): 30 00
        30 48(72):
            06 03(03): 55 1D 20     (2.5.29.32 CP 证书策略)
            04 41(65):
                30 3F(63):
                    30 3D(61):
                        06 08(08): 60 81 1C 86 EF 2A 01 02  (2.16.156.112554.1.2)
                        30 31(49):
                            30 2F(47):
                                06 08(08): 2B 06 01 05 05 07 02 01 (1.3.6.1.5.5.7.2.1)
                                           (http://www.cfca.com.cn/us/us-15.htm)
                                16 23(35): 68 74 74 70 3A 2F 2F 77 77 77 2E 63 66 63 61 2E 63 6F 6D 2E 63 6E 2F 75 73 2F 75 73 2D 31 35 2E 68 74 6D
        30 3A(58):
            06 03(03): 55 1D 1F     (2.5.29.31 cRLDistributionPoints CRL分发点)
            04 33(51):
                30 31(49):
                    30 2F(47):
                        A0 2D(45):
                            A0 2B(43):      (687474703a2f2f3231302e37342e34322e332f4f434131312f534d322f63726c31343535302e63726c)
                                86 29(41): 68 74 74 70 3A 2F 2F 32 31 30 2E 37 34 2E 34 32 2E 33 2F 4F 43 41 31 31 2F 53 4D 32 2F 63 72 6C 31 34 35 35 30 2E 63 72 6C
        30 0E(14):
            06 03(03): 55 1D 0F     (2.5.29.15)
            01 01(01): FF           (true)
            04 04(04):
                03 02(02): 06 C0    (06c0)
        30 1D(29):
            06 03(03): 55 1D 0E     (2.5.29.14)
            04 16(22):              (17c1b23d725040d7956e9070908ad74a25064fa9)
                04 14(20): 17 C1 B2 3D 72 50 40 D7 95 6E 90 70 90 8A D7 4A 25 06 4F A9
        30 1D(29):
            06 03(03): 55 1D 25     (2.5.29.37 extKeyUsage 扩展密钥用法)
            04 16(22):
                30 14(20):
                    06 08(08): 2B 06 01 05 05 07 03 02  (1.3.6.1.5.5.7.3.2 clientAuth 客户端认证)
                    06 08(08): 2B 06 01 05 05 07 03 04  (1.3.6.1.5.5.7.3.4)
 */
- (NSArray<CertExtension *> *)extensions:(char *)data begin: (int)begin length: (CertItemLength *)length {
    int type = data[begin];         // 获取Extensions类型信息
    if ((uint8_t)type != 0xa3) {    // Extensions的类型是0xa3
        return @[];
    }
    
    // 计算Extensions的长度信息：A3 82 01 07:
    int i = begin + 1 + length.lenLen;      // 偏移：类型0xa3
    
    // 计算最外层数组的长度信息：  30 82 01 03:
    CertItemLength *slength = [[CertItemLength alloc] initWithData:data index:i+1];
    i += 1 + slength.lenLen;        // 偏移：类型0xa0
    
    NSMutableArray<CertExtension *> *array = [NSMutableArray array];
    // 遍历数组
    while (i < begin + 1 + length.len + length.lenLen) {
        // 计算数组的长度信息 30 1F(31):
        slength = [[CertItemLength alloc] initWithData:data index:i+1];
        NSData *exdata = [NSData dataWithBytes:data+i length:1+slength.lenLen+slength.len];
        if ([CertExtension isValid:exdata] == NO) {
            break;
        }
        [array addObject:[[CertExtension alloc] initWithData:exdata]];
        i += 1 + slength.len + slength.lenLen;
    }
    return array;
}


// base64解码
- (NSData *)decodeBase64Info: (NSString *)data {
    NSUInteger len = data.length / 4 * 3;
 
    int textLen = 0;
    NSMutableData *certData = [NSMutableData data];
    [certData setLength:len + 1];
    char *cert = (char *)[certData bytes];
    
    NSMutableData *bit = [NSMutableData data];
    [bit setLength:4];
    char *base64Bit = (char *)[bit bytes];
    for (uint i = 0; i < data.length; i += 4) {      // info.length
        for (uint j = 0; j < 4; j++) {
            unichar c = [data characterAtIndex:i + j];
            base64Bit[j] = kBase64DecodeChars[c];
        }
        cert[textLen]     = ((base64Bit[0] & 0x3f) << 2) | ((base64Bit[1] & 0x30) >> 4);
        cert[textLen + 1] = ((base64Bit[1] & 0xf)  << 4) | ((base64Bit[2] & 0x3c) >> 2);
        cert[textLen + 2] = ((base64Bit[2] & 0x3)  << 6) | (base64Bit[3] & 0x3f);
        textLen += 3;
    }
    
    cert[textLen] = '\0';
    return certData;
}

- (void)printCert {
    printf("\nCertificate :\n");
    printf("\t%-14s: %s\n", @"version".UTF8String, self.certficate.version.UTF8String);
    printf("\t%-14s: %s\n", @"serialNumber".UTF8String, self.certficate.serialNumber.UTF8String);
    NSMutableString *signature = [NSMutableString string];
    for (int i = 0; i < self.certficate.signature.count; i++) {
        if (i > 0) {
            [signature appendString:@", "];
        }
        [signature appendFormat:@"%@(%@), ", self.certficate.signature[i], [CertOID oid: self.certficate.signature[i]]];
    }
    printf("\t%-14s: %s\n", @"signature".UTF8String, signature.UTF8String);
    
    NSMutableString *issuer = [NSMutableString string];
    for (int i = 0; i < self.certficate.issuer.count; i++) {
        if (i > 0) {
            [issuer appendString:@", "];
        }
        [issuer appendFormat:@"%@=%@", [CertOID oid:self.certficate.issuer[i][0]], self.certficate.issuer[i][1]];
    }
    printf("\t%-14s: %s\n", @"issuer".UTF8String, issuer.UTF8String);
    printf("\t%-14s: %s\n", @"notbefore".UTF8String, self.certficate.notBefore.UTF8String);
    printf("\t%-14s: %s\n", @"notAfter".UTF8String, self.certficate.notAfter.UTF8String);
    NSMutableString *subject = [NSMutableString string];
    for (int i = 0; i < self.certficate.subject.count; i++) {
        if (i > 0) {
            [subject appendString:@", "];
        }
        [subject appendFormat:@"%@=%@", [CertOID oid:self.certficate.subject[i][0]], self.certficate.subject[i][1]];
    }
    printf("\t%-14s: %s\n", @"subject".UTF8String, subject.UTF8String);
    
    printf("\t%-14s: \n\t[\n", @"publicKeyInfo".UTF8String);
    printf("\t\t%s\n\t]\n", [self.certficate.publicKeyInfo.description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t\t"].UTF8String);
    
    printf("\t%-14s: \n\t[\n", @"extensions".UTF8String);
    for (int i = 0; i < self.certficate.extensions.count; i++) {
        NSString *extension = [self.certficate.extensions[i].description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t\t"];
        printf("\t\t[%d] = %s\n", i, extension.UTF8String);
    }
    
    NSMutableString *signatureAlgorithm = [NSMutableString string];
    for (int i = 0; i < self.signatureAlgorithm.count; i++) {
        if (i > 0) {
            [signatureAlgorithm appendString:@", "];
        }
        [signatureAlgorithm appendFormat:@"%@(%@)", self.signatureAlgorithm[i], [CertOID oid: self.signatureAlgorithm[i]]];
    }
    printf("\t]\n");
    printf("对证书进行签名所用的算法:   %s\n", signatureAlgorithm.UTF8String);
    printf("对证书签名后得到的数字签名: %s\n", self.certficateSignature.UTF8String);
}

@end
